﻿using System;
using System.Collections;
using System.IO;
using System.IO.IsolatedStorage;
using System.Security.Principal;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace MCEMediaManager
{
    [Serializable]
    public class DataStoreHashTable : Hashtable
    {
        // Application store file name.  Using the entry 
        // assembly name with added .dat extension
        private string dataStoreFileName = string.Empty;
        private bool autoSave = true;
        private bool isDirty = false;

        // The default constructors.
        public DataStoreHashTable(string filepath)
            : this(filepath, "dat", true)
        {
        }

        // The default constructors.
        public DataStoreHashTable(string filepath, string ext)
            : this(filepath, ext, true)
        {
        }

        // The default constructors.
        public DataStoreHashTable(string filepath, bool auto)
            : this(filepath, "dat", auto)
        {
        }

        public DataStoreHashTable(string filepath, string ext, bool auto)
        {
            // append postfix to datastore filename
            dataStoreFileName = filepath + "." + ext;
            autoSave = auto;

            LoadData();
        }

        // This constructor is required for deserializing
        // our class from persistent storage.
        protected DataStoreHashTable(SerializationInfo info,
          StreamingContext context)
            : base(info, context)
        {
        }

        // Loads the application data from store
        public void LoadData()
        {
            // Check to see if file exists
            if (!File.Exists(dataStoreFileName))
            {
                // File does not exist, therefore do NOT try to DeSerialize it.
                return;
            }

            FileStream fs = new FileStream(dataStoreFileName,
                FileMode.Open, FileAccess.ReadWrite);

            if (fs != null)
            {
                try
                {
                    // DeSerialize the Hashtable from stream.
                    IFormatter bf = new BinaryFormatter();
                    Hashtable appData = (Hashtable)bf.Deserialize(fs);

                    // Enumerate through the collection and load our base Hashtable.
                    IDictionaryEnumerator enumerator = appData.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        this[enumerator.Key] = enumerator.Value;
                    }
                    isDirty = false;
                }
                catch (Exception)
                {
                    // unable to read from stream.
                    base.Clear();
                }
                finally
                {
                    fs.Close();
                }
            }
        }

        // Saves the application data to the storage.
        public void Save()
        {
            if (isDirty)
            {
                FileStream fs = new FileStream(dataStoreFileName,
                    FileMode.Create, FileAccess.ReadWrite);

                if (fs != null)
                {
                    try
                    {
                        BinaryFormatter bf = new BinaryFormatter();
                        bf.Serialize(fs, (Hashtable)this);
                        isDirty = false;
                    }
                    catch (Exception)
                    {
                        // unable to write to stream.
                    }
                    finally
                    {
                        fs.Close();
                    }
                }

                // set proper security access control for file
                try
                {
                    System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, null);
                    System.Security.Principal.NTAccount acct = sid.Translate(typeof(System.Security.Principal.NTAccount)) as System.Security.Principal.NTAccount;
                    string strEveryoneAccount = acct.ToString();

                    System.Security.AccessControl.FileSecurity sec = System.IO.File.GetAccessControl(dataStoreFileName);
                    sec.AddAccessRule(new System.Security.AccessControl.FileSystemAccessRule(
                                        strEveryoneAccount,
                                        System.Security.AccessControl.FileSystemRights.FullControl,
                                        System.Security.AccessControl.AccessControlType.Allow));

                    File.SetAccessControl(dataStoreFileName, sec);

                }
                catch (UnauthorizedAccessException)
                {
                    // permissions problem
                }
            }
        }

        public bool IsDirty
        {
            get
            {
                return isDirty;
            }

            set
            {
                isDirty = value;
            }
        }

        public override void Clear()
        {
            lock (this)
            {
                base.Clear();
                isDirty = true;

                if (autoSave)
                    Save();
            }
        }

        public override void Add(object key, object value)
        {
            lock (this)
            {
                if (base.Contains(key))
                {
                    base[key] = value;
                }
                else
                {
                    base.Add(key, value);
                }

                isDirty = true;

                if (autoSave)
                    Save();
            }
        }

        public override void Remove(object key)
        {
            lock (this)
            {
                base.Remove(key);
                isDirty = true;

                if (autoSave)
                    Save();
            }
        }
    }
}


